package org.activequant.util.store;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import org.activequant.store.IStoreService;

/**
 * Implements private store as a directory, with named objects stored as files within this directory.
 * <p>
 * FileStore implements IStoreService.<br/>
 * Holds the following associated variables:
 * <ul>
 * <li>storeDirectory(File)</li>
 * </ul>
 * <b>History:</b><br>
 *  - [03.01.2008] Created (Mike Kroutikov)<br>
 *
 *  @author Mike Kroutikov
 */
public class FileStore implements IStoreService {
	/**
	 * private final File storeDirectory;
	 */
	private final File storeDirectory;
	/**
	 * constructs a FileStore(implements IStoreService) using the given dir(String) path to set its associated storeDirectory(File).
	 * The given dir(String) path must point to an existing directory.
	 * @param dir
	 */
	public FileStore(String dir) {
		this(new File(dir));
	}
	/**
	 * constructs a FileStore(implements IStoreService) using the given dir(File) to set its associated storeDirectory(File).
	 * The given dir(File) must be an existing directory.
	 * @param dir
	 */
	public FileStore(File dir) {
		if(!dir.exists() || !dir.isDirectory()) {
			throw new IllegalArgumentException("store directory [" + dir + "] does not exist");
		}
		storeDirectory = dir;
	}
	
	/**
	 * Checks for invalid names (as we use names as filenames to store the objects).<br/>
	 * Validates/checks that the given name(String) doesn't start with a ".", and doesn't contain "/", "\\" or ".."
	 * @param name name to check.
	 */
	private static void checkName(String name) {
		if(name.startsWith(".")) {
			throw new IllegalArgumentException("name can not start with a '.': [" + name + "]");
		}
		
		if(name.contains("/") || name.contains("\\")) {
			throw new IllegalArgumentException("name can not contain a '/': [" + name + "]");
		}
		
		if(name.contains("..")) {
			throw new IllegalArgumentException("name can not contain '..': [" + name + "]");
		}
	}
	/**
	 * reads/returns a Serializable object by reading an object from the file named as the given name(String) (the file must be located in the associated storeDirectory(File) folder)
	 */
	public Serializable load(String name) throws Exception {
		checkName(name);
		
		File file = new File(storeDirectory, name);
		if(!file.exists()) {
			return null;
		} else {
			FileInputStream fileStream = new FileInputStream(file);
			ObjectInputStream stream = new ObjectInputStream(fileStream);
		
			Serializable out = (Serializable) stream.readObject();
			stream.close();
			fileStream.close();
			
			return out;
		}
	}
	/**
	 * writes/serializes the given object(Serializable) as a file named as the given name(String) into the associated storeDirectory(File) folder.
	 */
	public void save(String name, Serializable object) throws Exception {
		checkName(name);

		File file = new File(storeDirectory, name);

		if(object == null) {
			file.delete();
		} else {
			FileOutputStream fileStream = new FileOutputStream(file);
			ObjectOutputStream stream = new ObjectOutputStream(fileStream);
		
			stream.writeObject(object);
			stream.close();
			fileStream.close();
		}
	}
}
